#ifndef __SMS_HELPER__
#define __SMS_HELPER__
#include <string>
#include <vector>
#include <sms_json.hpp>
#include <opencv2/opencv.hpp>
#include <csignal>
#include <cstdlib>


namespace sms {

enum QoS {
    BestEffort = 1,
    Reliability = 2
};

nlohmann::json load_msg_types(std::string msg_type_dir="");
nlohmann::json def_msg(std::string type_need);

double get_time_sec();
std::string get_time_str_msec();
void msleep(int ms);
int check_topic_url(const std::string& topic_url);
int check_node_name(const std::string& node_name);
bool decode_msg(std::string& byte_msg, nlohmann::json& json_msg);
std::string encode_msg(nlohmann::json& json_msg);
nlohmann::json cvimg2sms(const cv::Mat& cvimg, const std::string format="jpg", const std::string frame_id="camera", const double timestamp=0.0);
cv::Mat sms2cvimg(const nlohmann::json& msg);
nlohmann::json cvimg2sms_mem(const cv::Mat& cvimg, const std::string mem_name, const std::string frame_id="camera", const double timestamp=0.0);
nlohmann::json pcl2sms_mem(const cv::Mat& pcl, const std::string mem_name, const std::string frame_id="lidar", const double timestamp=0.0);
cv::Mat sms2pcl(const nlohmann::json& msg);

void init_pubmem(const std::string mem_name);
void init_submem(const std::string mem_name);
void mem_cleanup(int signal);
void mem_init();

std::string _base64_encode(const std::string& input);
std::string _base64_decode(const std::string& input);
std::string _hex2string(const std::string &hex_data);
int _index_msg_header(std::string& data);
int _decode_msg_header(std::string& data);
void _check_msg(std::string& data, std::vector<std::string>& checked_msgs, std::vector<std::string>& parted_msgs, std::vector<int>& parted_lens);

std::vector<std::string> _split(const std::string& srcstr, const std::string& delimeter);
bool _startswith(const std::string& str, const std::string& start);
bool _endswith(const std::string& str, const std::string& end);
std::string _trim(const std::string& str);

bool _is_file_exist(std::string& fn);
void _list_dir(std::string dir, std::vector<std::string>& files, std::string suffixs="", std::string prefix="", bool r=false);
std::string _get_pdir(const std::string& path);


class Rate
{
public:
    Rate(double freq);
    ~Rate();
    void sleep();
private:
    double _default_dt;
    double _freq;
    double _sleep_dt;
    double _last_time;
    double _p;
};


class RunStat
{
public:
    RunStat() {}
    ~RunStat() {}
private:
    static RunStat* p;
public:
    static RunStat* instance()
    {
        return p;
    }
    nlohmann::json shm_pubs;
    nlohmann::json shm_subs;
    std::vector<char*> shm_ptrs;
};


inline const nlohmann::json ERROR_CODE_BOOK = {
    {"101", "Topic parsing error."},
    {"201", "topic_url wrong, at least 2 chars."},
    {"202", "topic_url wrong, need started with '/'."},
    {"203", "topic_url wrong, only to use 'a-z', '0-9', '_' or '/'."},
    {"204", "topic_url wrong, as the same as the existing."},
    {"205", "The topic_type you specified does not exist, please check the spelling or add the type to the msgs."},
    {"206", "Publisher/Subscriber does not include the topic_type and url fields."},
    {"207", "Uploaded unregistered topic."},
    {"208", "The topic type uploaded does not match the registered topic type."},
    {"209", "Cannot register as both a publisher and a subscriber."},
    {"210", "node_name wrong, at least 2 chars."},
    {"211", "node_name wrong, only to use 'a-z', '0-9' or '_'."},
    {"212", "Parameter does not include the node_name field."},
    {"213", "Cannot register Parameter with a publisher or a subscriber."},
    {"214", "node_name wrong, already exists."},
    {"215", "The current parameter node is not registered."},
    {"216", "node_name wrong, cannot start with '_'."},
    {"217", "param_key wrong, at least 2 chars."},
    {"218", "param_key wrong, only to use 'a-z', '0-9' or '_', except for the first '/'."},
    {"219", "param_key wrong, cannot start with '_'."},
    {"220", "global_param_key wrong, at least 6 chars."},
    {"221", "global_param_key wrong, only to use 'a-z', '0-9', '_' or '/'."},
    {"222", "global_param_key wrong, should start with '/'."},
    {"223", "_global param node cannot create new parameters, only update parameters."},
    {"224", "Service/Client does not include request_type, response_type and url fields."},
    {"225", "Cannot register as both a service and a client."},
    {"226", "service_url wrong, as the same as the existing."},
    {"227", "The request_type/response_type you specified does not exist, please check the spelling or add the type to the msgs."},
    {"228", "Request/Response by unregistered client."},
    {"229", "The request/response type does not match the registered request/response type."},
    {"230", "Cannot publish a topic with the same registered url but a different type."},
    {"231", "Cannot subscribe a topic with the same registered url but a different type."},
    {"232", "Cannot request a topic with the same registered url but a different type."},
    {"240", "Please check the topic_type returned in your callback, as it does not match the definition."},
    {"300", "The send queue is full, data loss occurred, please check the sending frequency."},
    {"501", "When the topic type != memory_msgs::, calling cvimg2sms_mem will return a null value."}
};

std::string ec2str(int ec);

}


#endif
